package com.yuandian.management.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuandian.api.management.entity.ConfReturnCode;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.bpm.common.security.util.SecurityUtils;
import com.yuandian.constant.Constants;
import com.yuandian.enums.ResultCodeEnum;
import com.yuandian.management.mapper.ConfReturnCodeMapper;
import com.yuandian.management.service.ConfReturnCodeService;
import com.yuandian.management.vo.CodeDetailsExcelVo;
import com.yuandian.utils.poi.BatchDataResult;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 返回码配置表-Service实现
 *
 * @author zfsn
 * @date 2023-3-28
 */
@Service
public class ConfReturnCodeServiceImpl extends ServiceImpl<ConfReturnCodeMapper, ConfReturnCode>
		implements ConfReturnCodeService {


	@Autowired
	ConfReturnCodeMapper confReturnCodeMapper;

	private static Map<String, Integer> levelMap = new HashMap<>();
	private static Map<String, Integer> typeMap = new HashMap<>();
	private static Map<Integer, String> typeMap2 = new HashMap<>();

	static {
		levelMap.put("提示", 1);
		levelMap.put("一般", 2);
		levelMap.put("重大", 3);
		levelMap.put("紧急", 4);
		levelMap.put("正常", 5);
		typeMap.put("WEB返回码", 1);
		typeMap.put("中间件返回码", 2);
		typeMap.put("数据库返回码", 3);
		typeMap.put("自定义返回码", 4);
		typeMap2.put(1, "WEB返回码");
		typeMap2.put(2, "中间件返回码");
		typeMap2.put(3, "数据库返回码");
		typeMap2.put(4, "自定义返回码");
	}

	/**
	 * 分页查询
	 *
	 * @param confReturnCode 筛选条件
	 * @return 通用返回对象
	 */
	@Override
	public Page<ConfReturnCode> listPage(ConfReturnCode confReturnCode) {
		return confReturnCodeMapper.listpage(new Page<>(confReturnCode.getPageNum(), confReturnCode.getPageSize()), confReturnCode);
	}

	/**
	 * 新增数据
	 *
	 * @param confReturnCode 实例对象
	 * @return 通用返回对象
	 */
	@Override
	public R<String> saveReturnCode(ConfReturnCode confReturnCode) {
		if (!checkReturnCodeNameDuplicates(confReturnCode)) {
			confReturnCode.setCreateBy(SecurityUtils.getUser().getName());
			confReturnCode.setCreateTime(LocalDateTime.now());
			super.save(confReturnCode);
			return R.ok();
		}
		return R.failed(ResultCodeEnum.RETRUN_CODE_NAME_EXIST.getMsg());
	}

	/**
	 * 通过主键更新数据
	 *
	 * @param confReturnCode 实例对象
	 * @return 通用返回对象
	 */
	@Override
	public R<String> updateReturnCodeById(ConfReturnCode confReturnCode) {
		if (!checkReturnCodeNameDuplicates(confReturnCode)) {
			confReturnCode.setUpdateBy(SecurityUtils.getUser().getName());
			confReturnCode.setUpdateTime(LocalDateTime.now());
			confReturnCodeMapper.updateByID(confReturnCode);
			return R.ok();
		}
		return R.failed(ResultCodeEnum.RETRUN_CODE_NAME_EXIST.getMsg());
	}

	/**
	 * 获取返回码信息
	 *
	 * @param confReturnCode 实例对象
	 * @return 通用返回对象
	 */
	@Override
	public List<ConfReturnCode> getCodeDetail(ConfReturnCode confReturnCode) {
		return confReturnCodeMapper.getCodeDetail(confReturnCode);
	}

	/**
	 * 判断业务名称是否重复
	 *
	 * @param confReturnCode 业务对象
	 */
	private boolean checkReturnCodeNameDuplicates(ConfReturnCode confReturnCode) {
		QueryWrapper<ConfReturnCode> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("name", confReturnCode.getName());
		queryWrapper.eq("type_id", confReturnCode.getTypeId());
		queryWrapper.eq("value", confReturnCode.getValue());
		if (confReturnCode.getId() != null) {
			queryWrapper.ne("id", confReturnCode.getId());
		}
		return (super.count(queryWrapper) > 0);
	}


	/**
	 * 下载专属指标导入模板
	 *
	 * @param response 响应上下文
	 */
	@Override
	public void importTemplate(HttpServletResponse response) throws IOException {
		// 1、设置response
		response.reset();
		response.setContentType("application/vnd.ms-excel");
		String fileName = URLEncoder.encode("返回码导入模板", "utf-8").replaceAll("\\+", "%20");
		response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");

		InputStream is = null;
		OutputStream os = null;
		try {
			// 2、获取文件输入流
			Resource resource = new ClassPathResource(Constants.IMPORT_RESULT_CODE_TEMPLATE_PATH);
			is = resource.getInputStream();

			// 3、获取输出流
			os = new BufferedOutputStream(response.getOutputStream());

			// 4、写入
			int len;
			byte[] bytes = new byte[1024];
			while ((len = is.read(bytes)) != -1) {
				os.write(bytes, 0, len);
			}
			os.flush();
		} finally {
			// 5、关闭资源
			if (is != null) {
				is.close();
			}
			if (os != null) {
				os.close();
			}
		}
	}

	@Override
	public void saveBatchExcelData(List<CodeDetailsExcelVo> dataList) {
		if (ObjectUtil.isNotEmpty(dataList)) {
			Set<ConfReturnCode> dataSet = new HashSet<>();

			List<ConfReturnCode> returnCodeList = this.list();
			if (!CollectionUtils.isEmpty(returnCodeList)) {
				for (CodeDetailsExcelVo excelVo : dataList) {
					ConfReturnCode vo = new ConfReturnCode();
					BeanUtils.copyProperties(excelVo, vo);
					vo.setName(excelVo.getName());
					vo.setValue(excelVo.getValue());
					vo.setLevel(levelMap.get(excelVo.getLevelName()));
					vo.setTypeId(typeMap.get(excelVo.getTypeName()));
					vo.setStatus("正常".equals(excelVo.getStateName()) ? 1 : 0);
					vo.setExplain(excelVo.getExplain());

					dataSet.add(vo);
				}
			}

			this.saveBatch(dataSet);
		}
	}

	/**
	 * 入库前-批量校验数据
	 *
	 * @param dataList
	 * @return
	 */
	@Override
	public BatchDataResult<CodeDetailsExcelVo> checkBatchExcelData(List<CodeDetailsExcelVo> dataList) {
		List<CodeDetailsExcelVo> successList = new ArrayList<>();
		List<CodeDetailsExcelVo> failList = new ArrayList<>();

		List<ConfReturnCode> returnCodeList = this.list();
		if (!CollectionUtils.isEmpty(returnCodeList)) {
			//1.返回码名称不为空 2.返回码值+类型名称+返回码名称的组合不能重复
			Set<String> keySet = returnCodeList.stream().map(code -> code.getTypeId() + code.getName() + code.getValue()).collect(Collectors.toSet());

			for (CodeDetailsExcelVo data : dataList) {
				StringBuilder sb = new StringBuilder()
						.append(typeMap.get(data.getTypeName()))
						.append(data.getName()).append(data.getValue());
				if (!keySet.contains(sb.toString())) {
					successList.add(data);
				} else {
					failList.add(data);
				}
			}
		}
		return new BatchDataResult<>(true, successList, failList);
	}

	@Override
	public boolean checkExcelData(CodeDetailsExcelVo data) {
		try {
			Field[] fields = data.getClass().getDeclaredFields();
			for (Field field : fields) {
				field.setAccessible(true);
				if (Objects.isNull(field.get(data))) {
					return false;
				}
			}
		} catch (IllegalAccessException e) {
			log.error(e.getMessage(), e);
			return false;
		}
		return true;
	}
}
